package com.hxzy.service.system.impl;


import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hxzy.common.TZXMConst;
import com.hxzy.dto.system.SysMenuAllDTO;
import com.hxzy.dto.system.SysMenuDTO;
import com.hxzy.entity.system.SysMenu;
import com.hxzy.mapper.system.SysMenuMapper;
import com.hxzy.service.system.SysMenuService;
import com.hxzy.vo.system.HxzyUser;
import com.hxzy.vo.system.MenuTreeVO;
import com.hxzy.vo.system.MenuVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public IPage<SysMenu> selectMenuTreeAll(SysMenuDTO sysMenuDTO) {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(sysMenuDTO.getMenuName())){
            queryWrapper.likeRight(SysMenu::getMenuName,sysMenuDTO.getMenuName());
        }
        if (Objects.nonNull(sysMenuDTO.getStatus())){
            queryWrapper.eq(SysMenu::getStatus,sysMenuDTO.getStatus());
        }

        Page<SysMenu> page = PageDTO.of(sysMenuDTO.getPage(), sysMenuDTO.getSize());

        return this.page(page,queryWrapper);
    }

    /**
     * 根据用户信息，查询相应的前端左边要显示菜单
     * @param hxzyUser 用户ID
     * @return
     */
    @Override
    public List<MenuVO> selectMenuTreeByUserId(HxzyUser hxzyUser) {
        final List<SysMenu> dbMenuList = new ArrayList<>();

        //现在以管理员查询所有数据为例
        if(hxzyUser.isSuperMan()){
            dbMenuList.addAll( super.baseMapper.selectMenuTreeAll());
        }else{
            dbMenuList.addAll(super.baseMapper.selectMenuTreeByUserId(hxzyUser.getSysUser().getId()));
        }


        List<MenuVO>  menuVOList=new ArrayList<>();
        //遍历数据库中所有的根节点
        dbMenuList.stream().filter(p -> p.getParentId().equals(0L)).forEach(s->{
            //s 就是SysMenu   变为   MenuVO
            MenuVO newMenuVO=new MenuVO();
            //对象里面的变量的值进行复制
            BeanUtils.copyProperties(s,newMenuVO);

            //遍历下级节点
            buildMenuTree(dbMenuList, newMenuVO);

            menuVOList.add(newMenuVO);

        });

        return menuVOList;
    }

    /**
     * 构建树型结构
     * @param dbMenuList
     * @param root
     * @return
     */
    private void buildMenuTree(  List<SysMenu> dbMenuList, MenuVO root){
        List<MenuVO>  childrenList=new ArrayList<>();
        //遍历数据库中所有的节点==parentId的值
        dbMenuList.stream().filter(p -> p.getParentId().equals(root.getId())).forEach(s->{
            //s 就是SysMenu   变为   MenuVO
            MenuVO newMenuVO=new MenuVO();
            //对象里面的变量的值进行复制
            BeanUtils.copyProperties(s,newMenuVO);
            childrenList.add(newMenuVO);
        });

        //放到父节点中
        if(childrenList.size()>0) {
            root.setChildren(childrenList);
        }
    }

    @Override
    public SysMenu findById(Long id) {
        return this.sysMenuMapper.findById(id);
    }

    @Override
    public List<MenuTreeVO> buildTreeMenu() {
        //判断redis是否存在
        String redisKey= TZXMConst.ROLE_MENU_KEY;
        Object redisValue = this.redisTemplate.opsForValue().get(redisKey);
        if(Objects.nonNull(redisValue)){
            List<MenuTreeVO>  menuTreeVOList = (List<MenuTreeVO>) redisValue;
            return menuTreeVOList;
        }


        //如果没有缓存查询数据库，进行递归操作
        List<MenuTreeVO>   menuTreeVOList=new ArrayList<>();
        List<SysMenu>   treeMenu = this.baseMapper.findTreeMenu();
        //遍历parentId==0L
        treeMenu.stream().filter(p->p.getParentId().longValue()==0L).forEach(p-> {
            MenuTreeVO  root=new MenuTreeVO();
            root.setId( p.getId());
            root.setLabel(p.getMenuName());

            //递归加载其它子节点
            recuriceChild(treeMenu,root);
            menuTreeVOList.add(root);
        });

        //存入到redis缓存中
        this.redisTemplate.opsForValue().set(redisKey, menuTreeVOList);

        return menuTreeVOList;
    }

    @Override
    public List<Long> selectMenuTreeByUserIdOwner(Long userId) {
        return this.baseMapper.selectMenuTreeByUserIdOwner(userId);
    }


    /**
     * 递归加载其它子节点
     * @param treeMenu
     * @param root
     */
    private void recuriceChild(List<SysMenu> treeMenu, MenuTreeVO root) {
        List<MenuTreeVO>   menuTreeVOList=new ArrayList<>();

        //遍历parentId== 上级节点.id
        treeMenu.stream().filter(p->p.getParentId().longValue()==root.getId().longValue()).forEach(p-> {
            MenuTreeVO  child=new MenuTreeVO();
            child.setId( p.getId());
            child.setLabel(p.getMenuName());

            //递归加载其它子节点
            recuriceChild(treeMenu,child);

            menuTreeVOList.add(child);
        });

        //判断是否有子节点
        if(menuTreeVOList.size()>0){
            root.setChildren(menuTreeVOList);
        }

    }

    @Override
    public List<MenuVO> buildTreeMenuAll(SysMenuAllDTO sysMenuAllDTO) {
        //如果没有缓存查询数据库，进行递归操作
        List<MenuVO>   menuVOList=new ArrayList<>();
        List<SysMenu>   treeMenu = this.baseMapper.selectMenuTreeAllTou(sysMenuAllDTO.getMenuName(), sysMenuAllDTO.getStatus());
        //遍历parentId==0L
        treeMenu.stream().filter(p-> p.getParentId() ==0L).forEach(p-> {
            MenuVO root = MenuVOTo(p);

            //递归加载其它子节点
            recuriceChildAll(treeMenu,root);
            menuVOList.add(root);
        });

        return menuVOList;
    }

    /**
     * 递归加载其它子节点
     * @param treeMenu
     * @param root
     */
    private void recuriceChildAll(List<SysMenu> treeMenu, MenuVO root) {
        List<MenuVO>   menuVOList=new ArrayList<>();

        //遍历parentId== 上级节点.id
        treeMenu.stream().filter(p->p.getParentId().longValue()==root.getId().longValue()).forEach(p-> {
            MenuVO child = MenuVOTo(p);

            //递归加载其它子节点
            recuriceChildAll(treeMenu,child);

            menuVOList.add(child);
        });

        //判断是否有子节点
        if(menuVOList.size()>0){
            root.setChildren(menuVOList);
        }

    }

    private MenuVO MenuVOTo(SysMenu p){
        MenuVO  root=new MenuVO();
        root.setId( p.getId());
        root.setMenuName(p.getMenuName());
        root.setParentId(p.getParentId());
        root.setOrderNum(p.getOrderNum());
        root.setPath(p.getPath());
        root.setComponent(p.getComponent());
        root.setQuery(p.getQuery());
        root.setIsFrame(p.getIsFrame());
        root.setIsCache(p.getIsCache());
        root.setMenuType(p.getMenuType());
        root.setVisible(p.getVisible());
        root.setStatus(p.getStatus());
        root.setPerms(p.getPerms());
        root.setIcon(p.getIcon());
        root.setCreateTime(p.getCreateTime());
        return root;
    }

    @Override
    public List<MenuVO> selectMenuAll(SysMenuAllDTO sysMenuAllDTO) {
        List<MenuVO>   menuVOList=new ArrayList<>();
        List<SysMenu>   treeMenu = this.baseMapper.selectMenuTreeAllTou(sysMenuAllDTO.getMenuName(), sysMenuAllDTO.getStatus());
        //遍历parentId==0L
        treeMenu.stream().forEach(p-> {
            MenuVO root = MenuVOTo(p);
            menuVOList.add(root);
        });

        return menuVOList;
    }

}